package main

import (
	"fmt"
	"reflect"
)

/**
  1.反射可以在运行是动态获取变量的各种信息，比如类型、类别
  2.如果是结构体变量，还可以获取到结构体本身的信息
  3.通过反射，可以修改变量的值，可以调用关联的方法
  4.使用反射，需要导入reflect
*/

func test_01(b interface{}) {

	rType := reflect.TypeOf(b)
	fmt.Println("rTyp =", rType) //rTyp = int

	rVale := reflect.ValueOf(b)
	fmt.Println("rVale =", rVale)
	fmt.Printf("rVale vale is: %v,and type is :%T \n", rVale, rVale) //rVale vale is: 100,and type is :reflect.Value

	//基本运算
	nVale := 120 + rVale.Int()
	fmt.Printf("nVavle = %v \n", nVale) //nVavle = 220

	//通过断言转换需要的类型
	iVale := rVale.Interface()
	n2Vale := iVale.(int)

	fmt.Printf("n2Vale = %v \n", n2Vale)

}

type Student struct {
	Name string
	Age  int
}

func test_02(b interface{}) {

	rType := reflect.TypeOf(b)
	fmt.Println("rTyp =", rType) //rTyp = main.Student

	rVale := reflect.ValueOf(b)
	fmt.Println("rVale =", rVale)                                    //rVale = {tom 10}
	fmt.Printf("rVale vale is: %v,and type is :%T \n", rVale, rVale) //rVale vale is: {tom 10},and type is :reflect.Value

	//通过断言转换需要的类型
	iVale := rVale.Interface()
	fmt.Printf("iVale vale is: %v,and type is :%T \n", iVale, iVale) //iVale vale is: {tom 10},and type is :main.Student
	n2Vale, ok := iVale.(Student)
	fmt.Printf("n2Vale vale is: %v,and type is :%T \n", n2Vale, n2Vale) //n2Vale vale is: {tom 10},and type is :main.Student
	fmt.Printf("n2Vale = %v \n", n2Vale)                                //n2Vale = {tom 10}

	if ok {
		fmt.Printf("stu.name :%v \n", n2Vale.Name) //stu.name :tom
	}
}

/**
  1.reflect.Value.Kind   获取变量的类别，返回的是一个常量
  2.Type 是类型，Kind是类别，他们可能是相同的，也可能不相同
  3.通过反射的来修改变量，注意当使用setxxx方法来设置，需要通过对应的指针类型来完成，这样才能改变传入的变量的值，同时需要使用到reflect.Value.Elem()方法
*/

func test_kind(b interface{}) {
	vKind := reflect.TypeOf(b).Kind()
	fmt.Printf("vKind:%v \n", vKind)

	sVale := reflect.ValueOf(b)
	sVale.Elem().SetString("hello,world")

	fmt.Printf("sVale type is :%T ,value is :%v \n", sVale, sVale)

	iVale := sVale.Elem().Interface()
	strValue := iVale.(string)
	fmt.Printf("strValue = %v \n", strValue)
}

func main() {

	//var num int =100
	//test_01(num)

	//stu := Student{
	//	Name: "tom",
	//	Age:  10,
	//}
	//test_02(stu)

	//unm2 := 100  //vKind:int
	str := "hello" //vKind:string
	test_kind(&str)
	fmt.Printf("str = %v \n", str)
}
